Elasticsearch Query DSL 查詢語法筆記
TLDR
- Query DSL 優勢:相比 Query String,DSL 支援 Nested 巢狀查詢、地理空間查詢、自訂評分(Function Score)及更複雜的布林邏輯,且結構清晰、錯誤訊息明確。
- Match Query:全文檢索的核心,
operator可控制邏輯(OR/AND),minimum_should_match支援靈活的數量與百分比規則,fuzziness支援模糊比對。 - Multi Match Query:提供
best_fields(預設,取最高分)、most_fields(加總分數)、cross_fields(跨欄位視為整體)等模式,適用於多欄位搜尋。 - Combined Fields Query:以詞彙為中心,將多個 text 欄位視為單一組合欄位,適合處理關鍵字分散在標題、摘要與內文的情況。
- Range Query:處理數值與日期範圍,日期查詢建議使用
format明確定義格式,並優先使用字串格式以避免數值被解析為毫秒時間戳記。 - Nested Query:當欄位為
nested型別時必須使用,能保留陣列元素內部欄位的關聯性,避免object型別扁平化導致的查詢錯誤。 - 效能警示:
wildcard與regexp查詢效能較差,應避免使用前導萬用字元,並限制max_determinized_states以防止資源耗盡。
Query DSL vs Query String
在正式環境中,Query DSL 是更推薦的選擇。相比 Query String,它具備以下優點:
- 功能完整性:Nested 查詢、地理空間查詢、自訂評分(
function_score)及複雜布林邏輯組合,皆僅能透過 Query DSL 實作。 - 結構清晰:JSON 結構明確定義了查詢型別與參數,易於維護與除錯,且錯誤訊息能精確指出問題欄位。
常用 Query DSL 語法
1. Match Query - 全文檢索查詢
用於全文檢索,會進行分詞與相關性評分。
- operator 參數:控制多個 token 的邏輯關係。
OR為預設值;AND要求文件必須包含所有詞。 - minimum_should_match:僅在
operator = "OR"時有效。支援正整數(絕對數量)、負整數(允許遺漏數量)、百分比(無條件捨去)及條件組合(如3<90%)。 - fuzziness:僅適用於
text欄位。建議設為AUTO,讓 Elasticsearch 自動根據詞長決定編輯距離。 - lenient:預設為
false。設為true可在型別不符時忽略該欄位,避免查詢拋出錯誤。 - zero_terms_query:當分詞後無 token 時,
none(預設)不回傳結果,all則回傳所有文件。
2. Multi Match Query - 多欄位查詢
在多個欄位中搜尋相同關鍵字。
- best_fields(預設):取最高分欄位,適合尋找「單一欄位最符合」的情況。
- most_fields:加總所有欄位分數,適合「多個相似欄位」的場景。
- cross_fields:將多個欄位視為一個大欄位,適合姓名、地址等跨欄位符合的查詢。
- phrase / phrase_prefix / bool_prefix:針對片語與前綴的特殊查詢類型,適用於自動完成或精確片語搜尋。
3. Combined Fields Query - 跨欄位詞彙查詢
採用以詞彙為中心的方式,將多個 text 欄位視為單一組合欄位。
- 限制:所有欄位必須是
text型別且使用相同的search_analyzer。 - 優勢:處理關鍵字分散在多個欄位(如標題、摘要、內文)時表現優異。
4. Match Phrase Query - 片語查詢
要求詞彙必須按順序出現。
- slop 參數:允許詞彙之間的最大間隔數,預設為
0(必須完全相鄰)。
5. Term 與 Terms Query - 精確符合
- Term:用於精確值查詢,不進行分詞。對
text欄位使用時,會比對分詞後的詞項(term)。 - Terms:類似 SQL 的
IN查詢。支援 Terms Lookup,可從現有文件中取得欄位值作為搜尋條件。
6. Range Query - 範圍查詢
用於數值與日期範圍。
- 日期處理:建議明確指定
format。若混用數值與字串,數值會被解釋為毫秒時間戳記,導致解析錯誤,建議統一使用字串格式。 - Date Math:支援
now、+1h、-1d等運算,並可透過||搭配捨入運算(如/d、/M)。
7. Exists Query - 欄位存在查詢
查詢某欄位是否存在(非 null)。
- 反向查詢:使用
bool查詢搭配must_not與exists。 - 注意事項:若欄位設定
index: false、doc_values: false或超過ignore_above限制,該欄位將無法被 exists 查詢偵測到。
8. Prefix, Wildcard 與 Regexp Query
- Prefix:查詢以特定字串開頭的文件。
- Wildcard:使用
*與?進行模糊查詢。避免使用前導萬用字元(如*term),以免觸發全表掃描。 - Regexp:支援正規表達式。效能最差,應盡量避免。Lucene 引擎不支援
^與$錨點,正規表達式預設匹配整個字串。
9. Fuzzy Query - 模糊查詢
容錯查詢,允許拼字錯誤。
- 建議:對於
text欄位,優先使用match查詢搭配fuzziness參數,而非直接使用fuzzy查詢,以確保查詢詞能經過分析器處理。
10. Nested Query - 巢狀物件查詢
用於查詢 nested 型別欄位,能保留陣列元素內部的關聯性。
- 問題情境:若使用
object型別,陣列會被扁平化,導致查詢時失去元素間的關聯(例如「John 給 5 分」會被誤判為「John 給 3 分」)。 - 解決方案:將欄位定義為
nested型別,並使用nested查詢,確保條件在「同一個子文件內」匹配。 - inner_hits:可透過此參數取得具體符合條件的巢狀物件,而非僅回傳主文件。
異動歷程
- 初版文件建立。